﻿
using LinqKit;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Ccteg.Common

{
    /// <summary>
    /// Lambda表达式拼接扩展
    /// </summary>
    public static class PredicateExtensions
    {
        /// <summary>
        /// 更新部分字段
        /// </summary>
        public static int UpdateEntity<T>(this DbContext context, T model, Expression<Func<T, object>>[] updatedProperties, bool IsCommit = true) where T : class
        {
            Type t = typeof(T);
            var a = t.GetType();
            int result = 0;
            context.Set<T>().Attach(model);
            if (updatedProperties.Any())
            {
                foreach (var property in updatedProperties)
                {
                    context.Entry<T>(model).Property(property).IsModified = true;
                }
            }
            if (IsCommit)
            {
                context.SaveChanges();
                //result = _UnitOfWork.Commit();
            }

            return result;
        }
        public static int UpdateAllEntity<T, B>(this DbContext context, T model, B bmodel, bool IsCommit = false) where T : class
        {
            Type t = typeof(T);

            int result = 0;
            context.Set<T>().Attach(model);
            if (bmodel != null)
            {
                foreach (var property in t.GetProperties())
                {
                    if (bmodel.GetType().GetProperties().Where(x => x.Name == property.Name).FirstOrDefault() != null)
                    {
                        if (property.Name.ToLower() != "id")
                            context.Entry<T>(model).Property(property.Name).IsModified = true;
                    }

                }
            }
            if (IsCommit)
            {
                context.SaveChanges();
            }

            return result;
        }
        /// <summary>
        /// 修改指定属性的单条数据
        /// </summary>
        /// <typeparam name="T">实体</typeparam>
        /// <param name="context">上下文</param>
        /// <param name="model">要修改的实体信息</param>
        /// <param name="expression">指定修改的字段</param>
        /// <param name="IsModified">是否未修改</param>
        public static bool ModifyEntityValue<T>(this DbContext context, T model, Expression<Func<T, object>> expression, bool IsModified = true)
            where T : class
        {
            try
            {
                context.Update(model);
                //4.1将 对象 添加到 EF中
                var entry = context.Entry<T>(model);
                //4.2先设置 对象的包装 状态为 Unchanged
                entry.State = EntityState.Unchanged;
                //4.3循环 被修改的属性名 数组
                foreach (var proInfo in expression.GetPropertyAccessList())
                {
                    if (!string.IsNullOrEmpty(proInfo.Name))
                        //4.4将每个 被修改的属性的状态 设置为已修改状态;后面生成update语句时，就只为已修改的属性 更新
                        entry.Property(proInfo.Name).IsModified = IsModified;
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
        public static Expression<Func<T, bool>> CheckNullAnd<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2, object Parameter)
        {
            if (Parameter == null)
            {
                return expression1;
            }
            var type = Parameter.GetType();
            if (type.Name == typeof(string).Name)
            {
                if (string.IsNullOrWhiteSpace((string)Parameter))
                {
                    return expression1;
                }
            }
            if (type.Name == typeof(int).Name)
            {

            }
            return PredicateBuilder.And(expression1, expression2);
        }


    }

    #region  Lambda表达式拼接扩展类 备份
    /// <summary>
    /// Lambda表达式拼接扩展类 备份
    /// </summary>
    public static class PredicateExtensionsOther
    {
        /// <summary>
        /// Lambda表达式拼接
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <param name="merge"></param>
        /// <returns></returns>
        //public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        //{
        //    var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
        //    var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
        //    return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        //}
        /// <summary>
        /// and扩展
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        //public static Expression<Func<T1, T2, bool>> And<T1, T2>(this Expression<Func<T1, T2, bool>> first, Expression<Func<T1, T2, bool>> second)
        //{
        //    return first.Compose(second, Expression.And);
        //}
        //public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        //{
        //    return first.Compose(second, Expression.And);
        //}



        /// <summary>
        /// or扩展
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        //public static Expression<Func<T1, T2, bool>> Or<T1, T2>(this Expression<Func<T1, T2, bool>> first, Expression<Func<T1, T2, bool>> second)
        //{
        //    return first.Compose(second, Expression.Or);
        //}
        //public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        //{
        //    return first.Compose(second, Expression.Or);
        //}

    }

    /// <summary>
    /// 
    /// </summary>
    //public class ParameterRebinder : ExpressionVisitor
    //{
    //    private readonly Dictionary<ParameterExpression, ParameterExpression> map;
    //    /// <summary>
    //    /// 
    //    /// </summary>
    //    /// <param name="map"></param>
    //    public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
    //    {
    //        this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
    //    }
    //    /// <summary>
    //    /// 
    //    /// </summary>
    //    /// <param name="map"></param>
    //    /// <param name="exp"></param>
    //    /// <returns></returns>
    //    public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
    //    {
    //        return new ParameterRebinder(map).Visit(exp);
    //    }
    //    /// <summary>
    //    /// 
    //    /// </summary>
    //    /// <param name="p"></param>
    //    /// <returns></returns>
    //    protected override Expression VisitParameter(ParameterExpression p)
    //    {
    //        ParameterExpression replacement;
    //        if (map.TryGetValue(p, out replacement))
    //        {
    //            p = replacement;
    //        }
    //        return base.VisitParameter(p);
    //    }
    //}

    //public static class PredicateExtensions
    //{
    //    //public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
    //    //{
    //    //    var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
    //    //    return Expression.Lambda<Func<T, bool>>(Expression.Or(expression1.Body, invokedExpression), expression1.Parameters);
    //    //}

    //    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Func<Expression<Func<T, bool>>> func)
    //    {
    //        Expression<Func<T, bool>> expr2 = func();
    //        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    //        return Expression.Lambda<Func<T, bool>>
    //              (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    //    }


    //    //public static Expression<Func<T, bool>> CheckNullAnd<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2, string value)
    //    //{

    //    //    if (string.IsNullOrWhiteSpace(value))
    //    //    {
    //    //        return expression1;
    //    //    }
    //    //    Expression<Func<T, bool>> expr2 = expression2();
    //    //    //        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    //    //    //        return Expression.Lambda<Func<T, bool>>
    //    //    //              (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    //    //    return PredicateBuilder.And(expression1, expression2);
    //    //}
    //}

    //public static class PredicateBuilder
    //{
    //    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    //    public static Expression<Func<T, bool>> False<T>() { return f => false; }

    //    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    //    {
    //        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    //        return Expression.Lambda<Func<T, bool>>
    //              (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    //    }

    //    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    //    {
    //        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    //        return Expression.Lambda<Func<T, bool>>
    //              (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
    //    }

    //    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Func<Expression<Func<T, bool>>> func)
    //    {
    //        Expression<Func<T, bool>> expr2 = func();
    //        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    //        return Expression.Lambda<Func<T, bool>>
    //              (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    //    }

    //    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Func<Expression<Func<T, bool>>> func)
    //    {
    //        Expression<Func<T, bool>> expr2 = func();
    //        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    //        return Expression.Lambda<Func<T, bool>>
    //              (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
    //    }
    //}


    #endregion
}
